package com.huntmobi.springsecuritydemo.base.config;

import com.huntmobi.springsecuritydemo.base.enums.APIEnum;
import com.huntmobi.springsecuritydemo.base.filter.*;
import com.huntmobi.springsecuritydemo.service.impl.SysUserServiceImpl;
import io.jsonwebtoken.Jwt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @BelongsProject: spring-security-demo
 * @Author: zouzhimin
 * @Date: 2020/11/19 9:18
 * @Description: security 配置
 **/
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SysUserServiceImpl sysUserService;
    @Autowired
    private JsonAuthenticationSuccessHandler jsonAuthenticationSuccessHandler;
    @Autowired
    private JsonAuthenticationFailureHandler jsonAuthenticationFailureHandler;
    @Autowired
    private JsonAuthenticationEntryPoint jsonAuthenticationEntryPoint;
    @Autowired
    private JsonLogoutSuccessHandler jsonLogoutSuccessHandler;
    @Autowired
    private JsonAccessDeniedHandler jsonAccessDeniedHandler;
    @Autowired
    private JwtFilter jwtFilter;

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 基于数据库方式，进行用户认证
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(sysUserService).passwordEncoder(new BCryptPasswordEncoder());
    }

    /**
     * 需要过滤的接口路径，在下面配置就好
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers(
                        APIEnum.VERCODE.getApi()
                        , APIEnum.DOC.getApi()
                        , APIEnum.FAVICONICO.getApi()
                        , APIEnum.v2ApiDocs.getApi()
                        , APIEnum.v2ApiDocsExt.getApi()
                        , APIEnum.SWAGGERRESOURCES.getApi()
                        , APIEnum.WEBJARS.getApi(),
                        APIEnum.LEFTMENU.getApi());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement()
                //禁用session,使用token
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling()
                //解决未登录，客户访问出现认证页面
                .authenticationEntryPoint(jsonAuthenticationEntryPoint)
                .and()
                //jwt拦截
                .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
                //自定义登录流程
                .addFilterAfter(jsonLoginFilter(), UsernamePasswordAuthenticationFilter.class)
                .logout()
                //退出成功处理，json数据返回
                .logoutSuccessHandler(jsonLogoutSuccessHandler)
                .and()
                .authorizeRequests()
                .anyRequest()
                //所有接口都要经过权限鉴权
                .access("@rbacAuthority.hasPermission(request,authentication)")
                .and()
                .exceptionHandling()
                //接口无权限处理
                .accessDeniedHandler(jsonAccessDeniedHandler)
                //禁用csrf
                .and()
                .csrf().disable();
    }

    @Bean
    public JsonLoginFilter jsonLoginFilter() throws Exception {
        JsonLoginFilter jsonLoginFilter = new JsonLoginFilter();
        //登录成功
        jsonLoginFilter.setAuthenticationSuccessHandler(jsonAuthenticationSuccessHandler);
        //登录失败
        jsonLoginFilter.setAuthenticationFailureHandler(jsonAuthenticationFailureHandler);
        jsonLoginFilter.setAuthenticationManager(authenticationManagerBean());
        return jsonLoginFilter;
    }
}
